//
//  Extensions.swift
//  cnswift-demo
//
//  Created by YangWei on 2021/1/3.
//  Copyright © 2021 YangWei. All rights reserved.
//

import UIKit

class Extensions: SWDBaseObject {
    
    class func run() {
        let extensions = Extensions()
        
        // 2 计算型属性
        extensions.computedProperties()
        
        // 3 构造器
        extensions.initializers()
        
        // 4 方法
        extensions.methods()
        
        // 4.1 可变实例方法
        extensions.mutatingInstanceMethods()
        
        // 5 下标
        extensions.subscripts()
        
        // 6 嵌套类型
        extensions.nestedTypes()
    }
    
    /// 2 计算型属性
    func computedProperties() {
        let title = "2 计算型属性";
        printStartLine(title)
        
        let oneInch = 25.4.mm
        print("One inch is \(oneInch) meters")
        // 打印“One inch is 0.0254 meters”
        let threeFeet = 3.ft
        print("Three feet is \(threeFeet) meters")
        // 打印“Three feet is 0.914399970739201 meters”
        
        // 可用于所有接受 Double 类型的数学计算中：
        let aMarathon = 42.km + 195.m
        print("A marathon is \(aMarathon) meters long")
        // 打印“A marathon is 42195.0 meters long”
        
        printEndLine(title)
    }
    
    /// 3 构造器
    func initializers() {
        let title = "3 构造器";
        printStartLine(title)
        
        // 使用默认构造器创建新的 Rect 实例
        let defaultRect = Rect()
        print(defaultRect)
        
        // 使用成员构造器创建新的 Rect 实例
        let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
                                  size: Size(width: 5.0, height: 5.0))
        print(memberwiseRect)
        
        // 左上角原点 is (2.5, 2.5) size 是 (3.0, 3.0)
        let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
                              size: Size(width: 3.0, height: 3.0))
        print(centerRect)
        
        printEndLine(title)
    }
    
    /// 3 构造器
    /// 定义支持 Rect 的结构体 Size，属性的默认值设置为 0.0
    struct Size {
        var width = 0.0, height = 0.0
    }
    
    /// 3 构造器
    /// 定义支持 Rect 的结构体 Point，属性的默认值设置为 0.0
    struct Point {
        var x = 0.0, y = 0.0
    }
    
    /// 3 构造器
    /// 定义一个 Rect 结构体表示一个几何矩形
    /// 所有的属性都提供了默认值 -> 自动获得默认构造器和成员构造器
    struct Rect {
        var origin = Point()
        var size = Size()
    }
    
    /// 4 方法
    func methods() {
        let title = "4 方法";
        printStartLine(title)
        
        // 对任意整形数值调用 repetitions(task:) 方法，来执行对应次数的任务：
        3.repetitions {
            print("Hello!")
        }
        // Hello!
        // Hello!
        // Hello!
        
        printEndLine(title)
    }
    
    /// 4.1 可变实例方法
    func mutatingInstanceMethods() {
        let title = "4.1 可变实例方法";
        printStartLine(title)
        
        var someInt = 3
        someInt.square()
        // someInt 现在是 9
        print(someInt)
        
        printEndLine(title)
    }
    
    /// 5 下标
    func subscripts() {
        let title = "5 下标";
        printStartLine(title)
        
        let i1 = 746381295[0]
        // 返回 5
        print("746381295[0] = ", i1)
        
        let i2 = 746381295[1]
        // 返回 9
        print("746381295[1] = ", i2)
        
        let i3 = 746381295[2]
        // 返回 2
        print("746381295[2] = ", i3)
        
        let i4 = 746381295[8]
        // 返回 7
        print("746381295[8] = ", i4)
        
        let i5 = 746381295[9]
        // 返回 0，就好像你进行了这个请求：0746381295[9]
        print("746381295[9] = ", i5)
        
        let i6 = 0746381295[9]
        print("0746381295[9] = ", i6)
        
        let i7 = 746381295[-1]
        print("746381295[-1] = ", i7)
        
        let i8 = 746381295[-10]
        print("746381295[-10] = ", i8)
        
        printEndLine(title)
    }
    
    /// 6 嵌套类型
    func nestedTypes() {
        let title = "6 嵌套类型";
        printStartLine(title)
        
        printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
        // 打印“+ + - 0 - 0 + ”
        
        printEndLine(title)
    }
    
    /// 6 嵌套类型
    // 输入一个 Int 类型的数组，依次迭代这些值。
    // 对于数组中的每一个整数，检查它的 kind 计算型属性，打印适当的描述
    func printIntegerKinds(_ numbers: [Int]) {
        for number in numbers {
            switch number.kind {
            case .negative:
                print("- ", terminator: "")
            case .zero:
                print("0 ", terminator: "")
            case .positive:
                print("+ ", terminator: "")
            }
        }
        print("")
    }
}

/// 2 计算型属性
/// 添加五个计算型实例属性：提供与距离单位相关工作的基本支持
/// 计算属性相关代码：都是只读计算型属性，表达式不包含 get 关键字（代码简化）
extension Double {
    var km: Double { return self * 1_000.0 }
    // Double 类型的 1.0 代表的是“一米”
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
    var ft: Double { return self / 3.28084 } // 英尺
}

/// 3 构造器
/// 扩展 Rect 结构体提供一个允许指定 center 和 size 的构造器
extension Extensions.Rect {
    init(center: Extensions.Point, size: Extensions.Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Extensions.Point(x: originX, y: originY), size: size)
    }
}

/// 4 方法
/// 给 Int 类型添加一个新的实例方法叫做 repetitions
/// 仅接收一个 () -> Void 类型的参数，它表示一个没有参数没有返回值的方法。
extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
}

/// 4.1 可变实例方法
/// 将原始值求平方
extension Int {
    mutating func square() {
        self = self * self
    }
}

/// 5 下标
/// 下标 [n] 返回从数字右侧开始的第 n 位数字
/// [-1] 表示左边第1位
extension Int {
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        
        // 额外处理为序号为负数
        var index = digitIndex
        if index < 0 {
            let strSelf = String(self)
            let length = strSelf.count
            index = length - (-index)
            
            if index < 0{
                // 向右越界 归于0
                index = 0
            }
        }
        
        for _ in 0..<index {
            decimalBase *= 10
        }
        // digitIndex 值没有足够的位数满足所请求的下标，那么下标的现实将返回 0
        // 将好像在数字的左边补上了 0：
        return (self / decimalBase) % 10
    }
}

/// 6 嵌套类型
/// 给 Int 添加一个嵌套枚举
extension Int {
    // 表示特定整数所代表的数字类型
    enum Kind {
        // 表示数字是负的、零的还是正的
        case negative, zero, positive
    }
    // 给 Int 添加一个计算型实例属性
    var kind: Kind {
        switch self {
        case 0:
            return .zero
        case let x where x > 0:
            return .positive
        default:
            return .negative
        }
    }
}
